/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2021 3snic Technologies Co., Ltd */

#ifndef SSSNIC_IPSEC_H
#define SSSNIC_IPSEC_H

#include "sssnic_dev.h"
#include "sssnic_cqm.h"
#include "qfc_obj.h"
#include "qfc_main.h"
#include "ssshw_comm_defs.h"

#ifndef SSSHW_BIG_ENDIAN
#define SSSHW_BIG_ENDIAN 0x4321
#endif

#ifndef SSSHW_LITTLE_ENDIAN
#define SSSHW_LITTLE_ENDIAN 0x1234
#endif


#define AEAD_ALG_SALT_LEN_32BIT 32
#define AEAD_ALG_KEY_LEN_UNIT 8
#define AEAD_ALG_KEY_BYTE_PAD 7
#define AEAD_ALG_KEY_LEN_SHIFT_UNIT 3

#define AEAD_ALG_KEY_LEN_128BIT 128
#define AEAD_ALG_KEY_LEN_192BIT 192
#define AEAD_ALG_KEY_LEN_256BIT 256
#define AEAD_ALG_KEY_LEN_512BIT 512

#define AEAD_ALG_AUTH_KEY_LEN_16B 16
#define AEAD_ALG_AUTH_KEY_LEN_24B 24
#define AEAD_ALG_AUTH_KEY_LEN_32B 32
#define AEAD_ALG_AUTH_KEY_LEN_64B 64

#define AES_GCM_KEY_LEN_16B 16
#define AES_GCM_KEY_LEN_24B 24
#define AES_GCM_KEY_LEN_32B 32

#define AEAD_ALG_ICV_LEN_32BIT 32
#define AEAD_ALG_ICV_LEN_64BIT 64
#define AEAD_ALG_ICV_LEN_96BIT 96
#define AEAD_ALG_ICV_LEN_128BIT 128
#define AEAD_ALG_ICV_LEN_192BIT 192
#define AEAD_ALG_ICV_LEN_224BIT 224
#define AEAD_ALG_ICV_LEN_256BIT 256
#define AEAD_ALG_ICV_LEN_384BIT 384
#define AEAD_ALG_ICV_LEN_512BIT 512

#define IPSEC_ESP_IV_8B 8
#define IPSEC_ESP_IV_16B 16

#define SSSEC_CRYPTO_XTS_BD_TYPE_XTS_EC 0
#define SSSEC_CRYPTO_XTS_BD_TYPE_ONLY_XTS 0
#define SSSEC_MAX_REPLAY_WIN_SIZE 64

enum hisec_ipsec_sa_ctx_op {
    SSSEC_IPSEC_OP_DEL_SA_CTX,
    SSSEC_IPSEC_OP_ADD_SA_CTX,
};

enum hisec_ipsec_offload_mode {
    SSSEC_IPSEC_OFFLOAD_MODE_DISABLE,
    SSSEC_IPSEC_OFFLOAD_MODE_XFRM,  /* linux XFRM IPsec offload */
    SSSEC_IPSEC_OFFLOAD_MODE_HWACC, /* HW IPsec offload accelaration */
};

enum hisec_ipsec_cipher_auth_enable {
    SSSEC_IPSEC_AUTH_CIPHER_DISABLE,
    SSSEC_IPSEC_ONLY_CIPHER_ENABLE,
    SSSEC_IPSEC_ONLY_AUTH_ENABLE,
    SSSEC_IPSEC_AUTH_CIPHER_ENABLE,
};

enum hisec_ipsec_mode {
    SSSEC_IPSEC_MODE_TRANSPORT,
    SSSEC_IPSEC_MODE_TUNNEL,
    SSSEC_IPSEC_MODE_NAT_TRAVERSE,
};

enum hisec_ipsec_proto {
    SSSEC_IPSEC_PROTO_ESP,
    SSSEC_IPSEC_PROTO_AH,

    HISEC_IPSEC_PROTO_MAX
};

enum hisec_ipsec_esp_next_proto {
    SSSEC_IPSEC_ESP_NEXT_PROTO_UDP,
    SSSEC_IPSEC_ESP_NEXT_PROTO_TCP,
    SSSEC_IPSEC_ESP_NEXT_PROTO_IPIP,
    SSSEC_IPSEC_ESP_NEXT_PROTO_IPV6,
};

enum hisec_ipsec_esp_iv_size {
    SSSEC_IPSEC_ESP_IV_128BIT, /* CBC esp hdr iv = 16byte */
    SSSEC_IPSEC_ESP_IV_64BIT,  /* GCM esp hdr iv = 8byte */
};

enum hisec_ipsec_esn_flag {
    SSSEC_IPSEC_ESN_FLAG_DISABLE,
    SSSEC_IPSEC_ESN_FLAG_ENABLE,
};

enum hisec_ipsec_alg_type {
    SSSEC_IPSEC_ALG_AEAD,
    SSSEC_IPSEC_ALG_ENC,
    SSSEC_IPSEC_ALG_AUTH,
    SSSEC_IPSEC_ALG_ENCAUTH,
};

enum hisec_crypto_alg_type {
    SSSEC_CRYPTO_ALG_AES_GCM,
    SSSEC_CRYPTO_ALG_AES_CBC,
    SSSEC_CRYPTO_ALG_AES_CTR,
    SSSEC_CRYPTO_ALG_HMAC_SHA1,
    SSSEC_CRYPTO_ALG_HMAC_SHA256,
    SSSEC_CRYPTO_ALG_HMAC_SHA384,
    SSSEC_CRYPTO_ALG_HMAC_SHA512,
    SSSEC_CRYPTO_ALG_HMAC_SM3,

    HISEC_CRYPTO_ALG_MAX
};

enum hisec_crypto_hmac_alg_type {
    SSSEC_CRYPTO_HMAC_PROHIBIT,
    SSSEC_CRYPTO_HMAC_SHA1,
    SSSEC_CRYPTO_HMAC_SHA224,
    SSSEC_CRYPTO_HMAC_SHA256,
    SSSEC_CRYPTO_HMAC_SHA512_224,
    SSSEC_CRYPTO_HMAC_SHA512_256,
    SSSEC_CRYPTO_HMAC_SHA512_384,
    SSSEC_CRYPTO_HMAC_SHA512_512,

    HISEC_CRYPTO_HMAC_MAX
};

enum hisec_crypto_cipher_alg {
    SSSEC_CRYPTO_CIPHER_ALG_AES,
    SSSEC_CRYPTO_CIPHER_ALG_SM4 = 3,
};

enum hisec_crypto_tx_channel_type {
    SSSEC_CRYPTO_TX_CHNL_TYPE_GCM,
    SSSEC_CRYPTO_TX_CHNL_TYPE_CBC,
    SSSEC_CRYPTO_TX_CHNL_TYPE_ASYM,

    HISEC_CRYPTO_TX_CHNL_TYPE_MAX
};

enum hisec_crypto_cipher_type {
    SSSEC_CRYPTO_CIPHER_TYPE_XTS,
    SSSEC_CRYPTO_CIPHER_TYPE_CTR,
    SSSEC_CRYPTO_CIPHER_TYPE_ECB,
    SSSEC_CRYPTO_CIPHER_TYPE_CBC,
    SSSEC_CRYPTO_CIPHER_TYPE_GCM = 6,
    SSSEC_CRYPTO_CIPHER_TYPE_OFB = 10,
};

enum hisec_crypto_bd_type {
    SSSEC_CRYPTO_BD_TYPE_SYM_CBCGCM,
    SSSEC_CRYPTO_BD_TYPE_SYM_XTS,
    SSSEC_CRYPTO_BD_TYPE_ASYM,
    SSSEC_CRYPTO_BD_TYPE_BYPASS,

    HISEC_CRYPTO_BD_TYPE_MAX
};

enum hisec_crypto_xts_ec_num {
    SSSEC_CRYPTO_XTS_EC_NUM1 = 1,
    SSSEC_CRYPTO_XTS_EC_NUM2 = 2,
    SSSEC_CRYPTO_XTS_EC_NUM3 = 3,
    SSSEC_CRYPTO_XTS_EC_NUM4 = 4,
    SSSEC_CRYPTO_XTS_EC_NUM5 = 5,
    SSSEC_CRYPTO_XTS_EC_NUM6 = 6,
    SSSEC_CRYPTO_XTS_EC_NUM7 = 7,
    SSSEC_CRYPTO_XTS_EC_NUM8 = 8,
    SSSEC_CRYPTO_XTS_EC_NUM9 = 9,
    SSSEC_CRYPTO_XTS_EC_NUM10 = 10,
    SSSEC_CRYPTO_XTS_EC_NUM11 = 11,
    SSSEC_CRYPTO_XTS_EC_NUM12 = 12,

    HISEC_CRYPTO_XTS_EC_NUM_MAX
};

enum hisec_crypto_cbcgcm_bd_len {
    SSSEC_CRYPTO_CBCGCM_BD_LEN_128B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_160B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_192B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_224B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_256B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_288B,
    SSSEC_CRYPTO_CBCGCM_BD_LEN_320B,
};

enum hisec_crypto_xts_bd_len {
    SSSEC_CRYPTO_XTS_BD_LEN_128B,
    SSSEC_CRYPTO_XTS_BD_LEN_160B,
    SSSEC_CRYPTO_XTS_BD_LEN_192B,
    SSSEC_CRYPTO_XTS_BD_LEN_224B,
    SSSEC_CRYPTO_XTS_BD_LEN_256B,
};

enum hisec_crypto_aes_key_len {
    SSSEC_CRYPTO_AES_KEY_LEN_128BIT,
    SSSEC_CRYPTO_AES_KEY_LEN_192BIT,
    SSSEC_CRYPTO_AES_KEY_LEN_256BIT,
};

enum hisec_crypto_auth_type {
    SSSEC_CRYPTO_AUTH_TYPE_HMAC,
    SSSEC_CRYPTO_AUTH_TYPE_NORMAL_HASH,
    SSSEC_CRYPTO_AUTH_TYPE_PROHIBIT,
    SSSEC_CRYPTO_AUTH_TYPE_GMAC = 3,
    SSSEC_CRYPTO_AUTH_TYPE_GCM = 6,
};

enum hisec_crypto_decry_status {
    SSSEC_CRYPTO_DECRY_SUCCESS,
    SSSEC_CRYPTO_DECRY_AUTH_FAILED,
    SSSEC_CRYPTO_DECRY_BAD_PROTO,
};

enum hisec_dh_phrase_stage {
    SSSEC_DH_STAGE1 = 1,
    SSSEC_DH_STAGE2 = 2,

    HISEC_DH_STAGE_MAX
};

enum hisec_dh_group_mode {
    SSSEC_DH_MODE_GROUP1 = 1,
    SSSEC_DH_MODE_GROUP2 = 2,
    SSSEC_DH_MODE_GROUP5 = 5,
    SSSEC_DH_MODE_GROUP14 = 14,
    SSSEC_DH_MODE_GROUP15 = 15,
    SSSEC_DH_MODE_GROUP16 = 16,
    SSSEC_DH_MODE_GROUP19 = 19,
    SSSEC_DH_MODE_GROUP20 = 20,
    SSSEC_DH_MODE_GROUP21 = 21,

    SSSEC_DH_MODE_MAX = 22
};

enum crypt_err_code {
    CRYPT_ERR_SUCCESS,
    CRYPT_ERR_FAILED,
    CRYPT_ERR_PARAM
};

typedef enum hisec_ipsec_sad_cmd {
    SSSEC_IPSEC_SAD_ADD_SA,
    SSSEC_IPSEC_SAD_DEL_SA,
    SSSEC_IPSEC_SAD_UPDATE_SA,
    SSSEC_IPSEC_SAD_FLUSH_SA,
} hisec_ipsec_sad_cmd_e;

typedef enum hisec_ipsec_spd_cmd {
    SSSEC_IPSEC_SPD_ADD_POLICY,
    SSSEC_IPSEC_SPD_DEL_POLICY,
    SSSEC_IPSEC_SPD_UPDATE_POLICY,
    SSSEC_IPSEC_SPD_FLUSH_POLICY,
} hisec_ipsec_spd_cmd_e;

typedef enum hisec_ipsec_spd_action {
    SSSEC_IPSEC_SPD_ACTION_BYPASS = 0,
    SSSEC_IPSEC_SPD_ACTION_ENCRYPTED = 1,
    SSSEC_IPSEC_SPD_ACTION_FWD,
} hisec_ipsec_spd_action_e;

typedef enum hisec_ipsecres_flag {
    SSSEC_IPSECRES_ALL = 0,
    SSSEC_IPSECRES_SP = 1,
    SSSEC_IPSECRES_SA = 2,

    HISEC_IPSECRES_MAX
} hisec_ipsecres_flag_e;

struct sssec_ipsec_alg_info {
    u8 cipher_alg_sel;
    u8 cipher_key_len_sel;
    u8 auth_type;
    u8 cipher_type;

    u8 esp_iv_size;
    u8 sha2_alg_sel;
    u8 sm3_md;
    u8 rsvd0;

    u16 cipher_key_len_byte;
    u16 auth_key_len;   /* in byte */
    u16 auth_trunc_len; /* in byte */
    u16 rsvd1;
    u32 icv_mac_len; /* in byte */

    u32 cipher_key[8];
    u32 auth_key[8];
    u32 salt;
};

#define IPSEC_SA_CTX_SW_DW0_CA_EN_OFS 30
#define IPSEC_SA_CTX_SW_DW0_WORK_MODE_OFS 27
#define IPSEC_SA_CTX_SW_DW0_IPSEC_PROTO_OFS 24
#define IPSEC_SA_CTX_SW_DW0_AUTH_KEY_LEN_OFS 14
#define IPSEC_SA_CTX_SW_DW0_AUTH_TYPE_OFS 10
#define IPSEC_SA_CTX_SW_DW0_CIPHER_TYPE_OFS 6
#define IPSEC_SA_CTX_SW_DW0_CIPHER_KEY_LEN_SEL_OFS 4
#define IPSEC_SA_CTX_SW_DW0_CIPHER_ALG_SEL_OFS 2
#define IPSEC_SA_CTX_SW_DW0_ESP_IV_SIZE_OFS 0

#define IPSEC_SA_CTX_SW_DW1_SM3_MD_OFS 29
#define IPSEC_SA_CTX_SW_DW1_ESN_FLAG_OFS 27
#define IPSEC_SA_CTX_SW_DW1_MAC_LEN_OFS 20
#define IPSEC_SA_CTX_SW_DW1_TFC_PAD_LEN_OFS 12
#define IPSEC_SA_CTX_SW_DW1_TFC_PAD_VAL_OFS 4
#define IPSEC_SA_CTX_SW_DW1_SHA2_ALG_SEL_OFS 0

#define IPSEC_SA_CTX_SW_DW2_AUTH_OFFSET_OFS 16
#define IPSEC_SA_CTX_SW_DW2_CIPHER_OFFSET_OFS 0

#define IPSEC_SA_CTX_SW_DW3_RNG_REP_OFFSET_OFS 16
#define IPSEC_SA_CTX_SW_DW3_ESP_AH_OFFSET_OFS 0

#define SSSEC_IPSEC_SA_CTX_SW_DW0(ca_en, work_mode, ipsec_proto, auth_key_len, auth_type, cipher_type,                \
    cipher_key_len_sel, cipher_alg_sel, esp_iv_size)                                                                  \
    (((ca_en) << IPSEC_SA_CTX_SW_DW0_CA_EN_OFS) | ((work_mode) << IPSEC_SA_CTX_SW_DW0_WORK_MODE_OFS) |                \
        ((ipsec_proto) << IPSEC_SA_CTX_SW_DW0_IPSEC_PROTO_OFS) |                                                      \
        ((u32)(auth_key_len) << IPSEC_SA_CTX_SW_DW0_AUTH_KEY_LEN_OFS) |                                               \
        ((auth_type) << IPSEC_SA_CTX_SW_DW0_AUTH_TYPE_OFS) | ((cipher_type) << IPSEC_SA_CTX_SW_DW0_CIPHER_TYPE_OFS) | \
        ((cipher_key_len_sel) << IPSEC_SA_CTX_SW_DW0_CIPHER_KEY_LEN_SEL_OFS) |                                        \
        ((cipher_alg_sel) << IPSEC_SA_CTX_SW_DW0_CIPHER_ALG_SEL_OFS) |                                                \
        ((esp_iv_size) << IPSEC_SA_CTX_SW_DW0_ESP_IV_SIZE_OFS))

#define SSSEC_IPSEC_SA_CTX_SW_DW1(sm3_md, esn_flag, mac_len, tfc_pad_len, tfc_pad_val, sha2_alg_sel)                   \
    (((sm3_md) << IPSEC_SA_CTX_SW_DW1_SM3_MD_OFS) | ((esn_flag) << IPSEC_SA_CTX_SW_DW1_ESN_FLAG_OFS) |                 \
        ((u32)(mac_len) << IPSEC_SA_CTX_SW_DW1_MAC_LEN_OFS) | ((tfc_pad_len) << IPSEC_SA_CTX_SW_DW1_TFC_PAD_LEN_OFS) | \
        ((tfc_pad_val) << IPSEC_SA_CTX_SW_DW1_TFC_PAD_VAL_OFS) |                                                       \
        ((sha2_alg_sel) << IPSEC_SA_CTX_SW_DW1_SHA2_ALG_SEL_OFS))

#define SSSEC_IPSEC_SA_CTX_SW_DW2(auth_offset, cipher_offset)      \
    (((u32)(auth_offset) << IPSEC_SA_CTX_SW_DW2_AUTH_OFFSET_OFS) | \
        ((u32)(cipher_offset) << IPSEC_SA_CTX_SW_DW2_CIPHER_OFFSET_OFS))

#define SSSEC_IPSEC_SA_CTX_SW_DW3(rng_rep_offset, esp_ah_offset)    \
    (((rng_rep_offset) << IPSEC_SA_CTX_SW_DW3_RNG_REP_OFFSET_OFS) | \
        ((esp_ah_offset) << IPSEC_SA_CTX_SW_DW3_ESP_AH_OFFSET_OFS))

#define IPSEC_SA_CTX_ANTI_REP_DW4_WIN_OFS 24
#define IPSEC_SA_CTX_ANTI_REP_DW4_ESN_EN_RX_OFS 23
#define IPSEC_SA_CTX_ANTI_REP_DW10_ESN_EN_TX_OFS 30

#define SSSEC_IPSEC_SA_CTX_ANTI_REP_DW4(rep_win, esn_en_rx) \
    (((u32)(rep_win) << IPSEC_SA_CTX_ANTI_REP_DW4_WIN_OFS) | ((esn_en_rx) << IPSEC_SA_CTX_ANTI_REP_DW4_ESN_EN_RX_OFS))

#define SSSEC_IPSEC_SA_CTX_ANTI_REP_DW10(esn_en_tx) ((u32)(esn_en_tx) << IPSEC_SA_CTX_ANTI_REP_DW10_ESN_EN_TX_OFS)

/* CRYPT DRV to MPU Commands */
typedef enum hisec_mpu_cmd {
    SSSEC_MPU_CMD_SET_IPSEC_OFFLOAD_MODE = 2,
    SSSEC_MPU_CMD_GET_CRYPTO_STATS = 3,
    SSSEC_MPU_CMD_GET_IPSEC_SAD = 4,
    SSSEC_MPU_CMD_GET_IPSEC_SPD = 5,
    SSSEC_MPU_CMD_GET_IPSEC_ITEM_CNT = 6,

    SSSEC_MPU_CMD_MAX = 255
} hisec_mpu_cmd_type_e;

typedef enum hisec_npu_cmd_type {
    SSSEC_NPU_CMD_SET_IPSEC_SA, /* IPsec SA child context 256B */
    SSSEC_NPU_CMD_SET_IPSEC_SP, /* IPsec Secure Policy */
    SSSEC_NPU_CMD_CALC_DH,

    SSSEC_NPU_CMD_FLUSH_IPSEC_RES, /* IPsec flush resource */
    SSSEC_NPU_CMD_INIT_SCQC,
    SSSEC_NPU_CMD_DEINIT_SCQC,

    SSSEC_NPU_CMD_MAX = 255
} hisec_npu_cmd_type_e;

typedef struct tag_hisec_cmd_hdr {
    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 rsvd0 : 16;
            u32 channel_id : 8;
            u32 cmd_type : 8; /* cmd type */
#else
            u32 cmd_type : 8;
            u32 channel_id : 8; /* logical concurrency channel */
            u32 rsvd0 : 16;
#endif
        } bs;
        u32 value;
    } dw0;

    u32 cmd_sn;
    u32 rsvd1[2];
} sssec_cmd_hdr_s;


typedef struct tag_hisec_cmd_init_scqc {
    sssec_cmd_hdr_s cmdhdr;

    u32 scqn;
    u32 rsvd;
    u32 scqc[10];
} sssec_cmd_init_scqc_s;

typedef struct tag_hisec_cmd_deinit_scqc {
    sssec_cmd_hdr_s cmdhdr;

    u32 scqn;
    u32 resvd[11];
} sssec_cmd_deinit_scqc_s;

typedef struct tag_hisec_cmd_flush_ipsec_res {
    sssec_cmd_hdr_s cmdhdr;

    u16 func_id;
    u16 rsvd0;
    u32 flush_flag;
    u32 rsvd1;
} sssec_cmd_flush_ipsec_res_s;

typedef struct tag_hisec_sa_enc_info {
    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 proto : 8;     /* tcp/udp */
            u32 direction : 8; /* out/in */
            u32 mode : 8;      /* 0 transport/ 1 tunnel */
            u32 flag : 8;      /* 1 -esn */
#else
            u32 flag : 8;
            u32 mode : 8;
            u32 direction : 8;
            u32 proto : 8;
#endif
        } bs;
        u32 value;
    } enc_dw0;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 replaywindow : 16; /* 32-64 */
            u32 alg_type : 8;      /* 0- aead 1-enc 2-auth 3-enc & auth */
            u32 alg_standard : 8;  /* 0 - aes, 3 - SM4 */
#else
            u32 alg_standard : 8;
            u32 alg_type : 8;
            u32 replaywindow : 16;
#endif
        } bs;
        u32 value;
    } enc_dw1;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 enc_type : 8;        /* hisec_crypto_alg_type */
            u32 auth_type : 8;       /* hisec_crypto_alg_type */
            u32 cipher_key_len : 16; /* in  bit */
#else
            u32 cipher_key_len : 16;
            u32 auth_type : 8;
            u32 enc_type : 8;
#endif
        } bs;
        u32 value;
    } enc_dw2;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 auth_key_len : 16;   /* in bit  */
            u32 auth_trunc_len : 16; /* in bit  */
#else
            u32 auth_trunc_len : 16;
            u32 auth_key_len : 16;
#endif
        } bs;
        u32 value;
    } enc_dw3;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 icv_mac_len : 16; /* in bit  */
            u32 rsvd1 : 16;
#else
            u32 rsvd1 : 16;
            u32 icv_mac_len : 16;

#endif
        } bs;
        u32 value;
    } enc_dw4;

    u32 salt; /* 32bit */

    u32 pad[2];

    u32 cipher_key[8]; /* 128bit 192bit 256bit	*/
    u32 auth_key[8];   /* 256bit */
} sssec_sa_enc_info_s;

typedef struct tag_hisec_sa_tuples {
    u32 daddr[4]; /* ipv4 in daddr[0] */
    u32 spi;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 ipsec_proto : 8;
            u32 iptype : 8; /* 0-ipv4 1-ipv6 */
            u32 rsvd : 16;
#else
            u32 rsvd : 16;
            u32 iptype : 8;
            u32 ipsec_proto : 8;
#endif
        } bs;
        u32 value;
    } tup_dw0;

    u32 pad[2];
} sssec_sa_tuples_s;

/* IPsec SA msg 160B */
typedef struct tag_hisec_cmd_set_ipsec_sa {
    sssec_cmd_hdr_s cmdhdr; /* 16B */

    sssec_sa_tuples_s tuples; /* 32B */

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 opid : 8; /* 0-add 1-del 2-update 3-flush */
            u32 rsvd0 : 24;
#else
            u32 rsvd0 : 24;
            u32 opid : 8;
#endif
        } bs;
        u32 value;
    } sa_dw0;

    u32 scqn; /* used for scqe sa aging update msg notify */

    u32 pad[2];

    sssec_sa_enc_info_s enc_info;
} sssec_cmd_set_ipsec_sa_s;

typedef struct tag_hisec_sp_tuples {
    u32 saddr[4]; /* ipv4 in saddr[0] */
    u32 daddr[4]; /* ipv4 in daddr[0] */
    u32 sa_masklen;
    u32 da_masklen;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 dport : 16;
            u32 sport : 16;
#else
            u32 sport : 16;
            u32 dport : 16;
#endif
        } bs;
        u32 value;
    } tup_dw0;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 dport_mask : 16;
            u32 sport_mask : 16;
#else
            u32 sport_mask : 16;
            u32 dport_mask : 16;
#endif
        } bs;
        u32 value;
    } tup_dw1;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 ulp_proto : 8; /*  tcp/udp */
            u32 iptype : 8;    /* 0-ipv4 1-ipv6 */
            u32 rsvd0 : 16;
#else
            u16 rsvd0;
            u8 iptype;
            u8 ulp_proto;
#endif
        } bs;
        u32 value;
    } tup_dw2;

    u32 pad[3];
} sssec_sp_tuples_s;

/* IPsec SP msg 128B */
typedef struct tag_hisec_cmd_set_ipsec_sp {
    sssec_cmd_hdr_s cmdhdr;

    sssec_sp_tuples_s tuples;

    u32 spi;

    union {
        struct {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
            u32 ipsec_proto : 8; /* 50-esp 51-ah */
            u32 opid : 8;        /* 0-add 1-del 2-update */
            u32 action : 8; /* 0-bypass 1-encrypted */
            u32 rsvd0 : 8;
#else
            u32 rsvd0 : 8;
            u32 action : 8;
            u32 opid : 8;
            u32 ipsec_proto : 8;
#endif
        } bs;
        u32 value;
    } sp_dw0;

    u32 pad[10];
} sssec_cmd_set_ipsec_sp_s;

typedef struct tag_hisec_cmd_dh_param {
#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
    u16 generator;
    u8 dh_phase; /* 1-DH Phase1 2- DH Phase 2 */
    u8 dh_groupid;
#else
    u8 dh_groupid;
    u8 dh_phase; /* 1-DH Phase1 2- DH Phase 2 */
    u16 generator;
#endif

#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
    u16 privkey_len;
    u16 modp_len;
#else
    u16 modp_len;
    u16 privkey_len;
#endif

#if (SSSHW_BYTE_ORDER == SSSHW_LITTLE_ENDIAN)
    u16 rsvd0;
    u16 pubkey_len;
#else
    u16 pubkey_len;
    u16 rsvd0;
#endif

    u32 rsvd1[13];

    u32 modprime[128];    /* public prime number */
    u32 private_key[128]; /* private Xa */
    u32 public_key[128];  /* public Yb */
} sssec_cmd_dh_param_s;

typedef struct tag_hisec_cmd_calc_dh {
    sssec_cmd_hdr_s cmdhdr;

    /* writeback result PhyAddr */
    u32 buf_len;
    u32 buf_gpah;
    u32 buf_gpal;

    /* writeback result LogicalVirtualAddr */
    u32 buf_vah;
    u32 buf_val;

    /* detect memory tramp */
    u32 magic_h;
    u32 magic_l;

    u32 scqn;
    u32 rsvd[4];

    sssec_cmd_dh_param_s dh_param;
} sssec_cmd_calc_dh_s;

struct sssec_cmd_ipsec_offload_mode {
    struct ssshw_comm_info_head msg_head;

    u16 func_id;
    u8 offload_mode; /* 0-disable 1-xfrm offload 2-ipsec full offload */
    u8 rsvd1[5];
};

struct sssec_crypto_stats {
    u64 cryrx_auth_err;
    u64 cryrx_tfc_pad_err;
    u64 cryrx_other_err;
    u64 crytx_bd_err;
    u64 crytx_len_err;
};

struct sssec_cmd_cryptodev_stats {
    struct ssshw_comm_info_head msg_head;
    struct sssec_crypto_stats stats;
};

struct sssec_cmd_ipsec_item_cnt {
    struct ssshw_comm_info_head msg_head;

    u32 sp_item_cnt;
    u32 sa_item_cnt;
    u16 func_id;
    u16 pad;
};

typedef union {
    struct {
        u32 tbl_index;
        u32 cnt;
        u32 total_cnt;
    } tbl_arg;
    u32 args[4];
} ipsec_sml_tbl_args;

#define IPSEC_SML_TBL_BUF_MAX (768)

struct sssec_cmd_sml_table {
    struct ssshw_comm_info_head msg_head;
    u16 func_id;
    u32 tbl_type;
    ipsec_sml_tbl_args args;
    u8 tbl_buf[IPSEC_SML_TBL_BUF_MAX];
};

#define SSSNIC_IPSEC_SADB_BITS 16
#define SSSNIC_IPSEC_SA_HASH_TBL_SIZE (1 << (SSSNIC_IPSEC_SADB_BITS))
#define SSSNIC_IPSEC_SP_HASH_TBL_SIZE (1 << (SSSNIC_IPSEC_SADB_BITS))

#define SSSNIC_IPSEC_TOTAL_SA_CTX_NUM (128 * 1024)
#define SSSNIC_IPSEC_PER_PF_SA_CTX_NUM (32 * 1024)
#define SSSNIC_IPSEC_SA_CTX_SIZE 512
#define SSSNIC_IPSEC_XID_RESERVE_NUM 2

/* esp_tailer = tfc_padding_len + pad_length + 2B(Pad Length Next Header) */
#define SSSNIC_IPSEC_ESP_TAILER_FMT_LEN 2

#define SSSNIC_IS_IP_IPSEC_OFFLOAD(xs, skb)	\
	(!(xs)->xso.offload_handle ||	\
	((skb)->protocol != htons(ETH_P_IP) &&	\
	 (skb)->protocol != htons(ETH_P_IPV6)))

struct sssnic_ipsec_stats {
	u64 rx_ipsec_packets;
	u64 rx_ipsec_secure_policy_errors;
	u64 rx_ipsec_xfrm_state_errors;
	u64 rx_ipsec_xfrm_offload_errors;

	u64 tx_ipsec_packets;
	u64 tx_ipsec_secure_policy_errors;
	u64 tx_ipsec_xfrm_state_errors;
	u64 tx_ipsec_ip_errors;
	u64 tx_ipsec_tailer_errors;

#ifdef HAVE_NDO_GET_STATS64
	struct u64_stats_sync		syncp;
#else
	struct u64_stats_sync_empty	syncp;
#endif
};

struct sssnic_ipsec_xmap {
	void *sa_ctx;
};

/* IPsec SA Database */
struct sssnic_ipsec {
	struct sssnic_nic_dev *nic_dev;
	struct hlist_head sadb[SSSNIC_IPSEC_SA_HASH_TBL_SIZE];
	spinlock_t sadb_lock; /* lock SAD */
	bool no_trailer;
	struct sssnic_ipsec_stats stats;
	struct workqueue_struct *esn_wq;
	struct sssnic_ipsec_xmap *xmap; /* xid map to sa item table */
};

extern unsigned char ipsec_work_mode;
int sssnic_init_ipsec_offload(struct sssnic_nic_dev *nic_dev);
void sssnic_cleanup_ipsec_offload(struct sssnic_nic_dev *nic_dev);
/* *
 * @brief ssscec_reg_cqm_service - Register Context and Queue Management service
 * @param hwdev: device pointer to hwdev
 * @param reg_temp: app register cqm service template
 * @retval zero: success
 * @retval non-zero: failure
 */
int ssscec_reg_cqm_service(void *hwdev, struct ssshw_tag_service_register_template *reg_temp);

/* *
 * @brief ssscec_unreg_cqm_service - Unregister Context and Queue Management service
 * @param hwdev: device pointer to hwdev
 * @param service_type: app identify
 * @retval NULL
 */
void ssscec_unreg_cqm_service(void *hwdev, u32 service_type);

int ssscec_set_ipsec_policy(void *hwdev, sssec_cmd_set_ipsec_sp_s *sp_msg);
int ssscec_set_ipsec_sa(void *hwdev, sssec_cmd_set_ipsec_sa_s *sa_msg);
int ssscec_flush_ipsec_resource(void *hwdev, u32 flush_flag);

int ssscec_set_ipsec_offload_mode(void *hwdev, u8 offload_mode);
int ssscec_get_crypto_stats(void *hwdev, struct sssec_crypto_stats *stats);

#endif /* _SSSNIC_IPSEC_H_ */
